/*
 Copyright 2017 Intel Corporation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
------------------------------------------------------------------------------
*/

#pragma once

#include <Python.h>
#include <string>

// This is the identifier for the genesis block
const std::string NULL_IDENTIFIER = "0000000000000000";
const int IDENTIFIER_LENGTH = 16;
const double MINIMUM_WAIT_TIME = 1.0;

// Signup data is an ephemeral thing that is used in the creation of signup
// info.  When a request is made to create signup info, we first will create
// the signup data.  Part of the generated signup data (enclave quote and PSE
// manifest) are used to create the IAS Attestation Verification Report (AVR).
// The signup data plus the AVR are then used to generate the signup info.
//
// Signup data is never meant to be used externally, thus the Python convention
// of prefixing the class name with an underscore.

class _SignupData
{
public:
    static _SignupData* CreateSignupData(
        const std::string& originatorPublicKeyHash
        );
    static std::string UnsealSignupData(
        const std::string& sealedSignupData
        );
    static void ReleaseSignupData(
        const std::string& sealedSignupData
        );
    // Signup data properties
    std::string poet_public_key;
    std::string pse_manifest;
    std::string enclave_quote;
    std::string sealed_signup_data;

protected:
    _SignupData(
        const std::string& originatorPublicKeyHash
        );
}; // class _SignupData

_SignupData* _create_signup_data(
    const std::string& originator_public_key_hash
    );

std::string unseal_signup_data(
    const std::string& sealed_signup_data
    );

void release_signup_data(
    const std::string& sealed_signup_data
    );

class SignupInfo
{
public:
    static SignupInfo* _SignupInfoFromSerialized(
        const std::string& serializedSignupInfo
        );

    std::string serialize() const
    {
        return this->serialized;
    }

    // Signup info properties
    std::string poet_public_key;
    std::string sealed_signup_data;
    std::string proof_data;
    std::string anti_sybil_id;

protected:
    SignupInfo(
        const std::string& serializedSignupInfo
        );

private:
    /*
    Json serialization of the signup info Parameters, this serves as the
    canonical representation of the signup info.
    */
    std::string serialized;
}; // class SignupInfo

SignupInfo* deserialize_signup_info(
    const std::string& serialized_signup_info
    );

class WaitTimer
{
public:
    static WaitTimer* _CreateWaitTimer(
        const std::string& sealedSignupData,
        const std::string& validatorAddress,
        const std::string& previousCertificateId,
        double localMean
        );

    static WaitTimer* _WaitTimerFromSerialized(
        const std::string& serializedTimer,
        const std::string& signature = ""
        );

    bool has_expired() const;

    std::string serialize() const
    {
        return this->serialized;
    }
    void deserialize(
        const std::string& serializedTimer
        );

public:
    // WaitTimer parameters
    double local_mean;
    double duration;
    std::string previous_certificate_id;
    double request_time;
    std::string validator_address;

    /*
    JSON serialization of the WaitTimer Parameters, this serves as the
    canonical representation of the WaitTimer. The signature field is
    used to verify that it has not be changed and that it was generated by a
    trusted source.
    */
    std::string serialized;
    /*
    Base64 encoded ECDSA signauture over the serialized WaitTimer using the
    PoET secret key generated for the validator when its signup info was
    created.  The enclave can use this to verify that the wait timer generated
    by the associated validator's enclave and the serialized timer has not
    changed.
    */
    std::string signature;

protected:
    WaitTimer(
        const std::string& sealedSignupData,
        const std::string& validatorAddress,
        const std::string& previousCertificateId,
        double localMean
        );
    WaitTimer(
        const std::string& serializedTimer,
        const std::string& signature = ""
        );
}; // class WaitTimer

WaitTimer* _create_wait_timer(
    const std::string& sealedSignupData,
    const std::string& validator_address,
    const std::string& previous_certificate_id,
    double local_mean
    );

WaitTimer* deserialize_wait_timer(
    const std::string& serialized_timer,
    const std::string& signature
    );

class WaitCertificate
{
 public:
    static WaitCertificate* _CreateWaitCertificate(
        const std::string& sealedSignupData,
        const WaitTimer* waitTimer,
        const std::string& blockHash
        );
    static WaitCertificate* _WaitCertificateFromSerialized(
        const std::string& serializedCertificate,
        const std::string& signature = ""
        );

    std::string identifier() const;
    std::string serialize() const;
    void deserialize(
        const std::string& serializeCertificate
        );

    // WaitCertificate Parameters
    std::string block_hash;
    double duration;
    double local_mean;
    std::string nonce;
    std::string previous_certificate_id;
    double request_time;
    std::string validator_address;

    /*
    Json serialization of the WaitCertificate Parameters, this serves as the
    canonical representation of the WaitCertificate. The signature field is
    used to verify that it has not be changed and that it was generated by a
    trusted source.
    */
    std::string serialized;
    /*
    Base64 encoded ECDSA signauture over the serialized WaitCerficate using the
    PoET secret key generated for the validator when its signup info was
    created.  The enclave can use this to verify that the wait timer generated
    by the associated validator's enclave and the serialized timer has not
    changed.
    */
    std::string signature;

protected:
    WaitCertificate(
        const std::string& sealedSignupData,
        const WaitTimer* waitTimer,
        const std::string& blockHash
        );
    WaitCertificate(
        const std::string& serializedCertificate,
        const std::string& signature = ""
        );
}; // class WaitCertificate

WaitCertificate* create_wait_certificate(
    const std::string& sealedSignupData,
    const WaitTimer* wait_timer,
    const std::string& block_hash
    );

WaitCertificate* deserialize_wait_certificate(
    const std::string& serialized_certificate,
    const std::string& signature
    );

bool _verify_wait_certificate(
    const std::string& serializedWaitCertificate,
    const std::string& waitCertificateSignature,
    const std::string& poetPublicKey
    );

class Poet
{
public:
    Poet(
        const std::string& dataDirectory,
        const std::string& enclaveModulePath,
        const std::string& spid
        );
    virtual ~Poet();
    std::string get_epid_group();
    void set_signature_revocation_list(
        const std::string& signature_revocation_list
        );

    std::string mr_enclave;         // hex encoding of the enclave measurement
    std::string basename;           // hex encoding of the basename
    std::string pse_manifest_hash;  // hex encoding of the PSE manifest hash
}; // class Poet

void InitializePoetEnclaveModule();
void _SetLogger(
    PyObject*
    );
bool _is_sgx_simulator();
